// Copyright (C) 2015, Alberto Corona <alberto@0x1a.us>
// All rights reserved. This file is part of core-utils, distributed under the
// GPL v3 license. For full terms please see the LICENSE file.

#![crate_type = "bin"]
#![crate_name = "ls"]
#![feature(path_ext)]

static VERS: &'static str = "0.1.0";
static PROG: &'static str = "ls";

extern crate getopts;
extern crate util;

use getopts::{Options};
use util::{Status};

use std::fs;
use std::env;
use std::io;
use std::fs::{PathExt};
use std::path::{PathBuf};

enum Format {
    Long,
    Short,
}

fn is_dot(dir: &PathBuf) -> bool {
    let dir_str = match dir.to_str() {
        Some(s) => { s },
        None => { panic!() },
    };
    if dir_str.starts_with(".") {
        return true;
    } else {
        return false;
    }
}

fn format_print(rel_path: &PathBuf, path: &PathBuf, format: &Format) {
    match format {
        &Format::Short => {
            if path.is_dir() {
                print!("{}/ ", rel_path.display());
            } else {
                print!("{} ", rel_path.display());
            }
        }
        &Format::Long => {
            if path.is_dir() {
                println!("{}/ ", rel_path.display());
            } else {
                println!("{} ", rel_path.display());
            }
        }
    };
}

fn print(path: &Vec<String>, format: Format, all: bool) -> io::Result<()> {
    for item in path.iter() {
        let fpath = PathBuf::from(item);
        if fpath.is_dir() {
            for entry in try!(fs::read_dir(&fpath)) {
                let entry = try!(entry);
                let rel_path = util::to_rel(&entry.path(), &fpath);
                match format {
                    Format::Short => {
                        if all {
                            format_print(&rel_path, &entry.path(), &format);
                        } else {
                            if !is_dot(&rel_path) {
                                format_print(&rel_path, &entry.path(), &format);
                            }
                        }
                    }
                    Format::Long => {
                        if all {
                            format_print(&rel_path, &entry.path(), &format);
                        } else {
                            if !is_dot(&rel_path) {
                                format_print(&rel_path, &entry.path(), &format);
                            }
                        }
                    }
                }
            }
        }
    }
    return Ok(());
}

fn print_usage(prog: &str, opts: Options) {
    let brief = format!("Usage: {} [OPTION]", prog);
    print!("{}", opts.usage(&brief));
    util::exit(Status::Ok);
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.optflag("h", "help", "Print the help menu");
    opts.optflag("", "version", "Print the version of ls");
    opts.optflag("a", "all", "Display hidden files");
    opts.optflag("l", "long", "Use the long listing option");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => {
            util::err(PROG, Status::Error, f.to_string());
            panic!(f.to_string())
        }
    };

    let mut current = Vec::new();
    current.push(String::from(env::current_dir().unwrap().to_str().unwrap()));

    let all = matches.opt_present("a");

    if matches.opt_present("h") {
        print_usage(PROG, opts);
    } else if matches.opt_present("version") {
        util::copyright(PROG, VERS, "2015", vec!["Alberto Corona"]);
    } else if matches.opt_present("l") {
        if !matches.free.is_empty() {
            print(&matches.free, Format::Long, all).ok();
        } else {
            print(&current, Format::Long, all).ok();
        }
    } else {
        if matches.free.is_empty() {
            print(&current, Format::Short, all).ok();
        } else {
            print(&matches.free, Format::Short, all).ok();
        }
    }
}
